//
// Authenticate_PAM.cpp
// libprotea
// Tools Library for the Protea Project / Functionality for user authentication via PAM
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// Please send correspondence to:
// 
// theproteaproject@gmail.com
//

#include "../defines.h"
#include "AppInterface.h"
#include "security.h"

#include "../defns.h"
using namespace ProteaApp1;

#ifdef USE_PAM
#include <security/pam_appl.h>
#endif


#ifdef USE_PAM
extern "C" {
int PAMCallback( int num_msg, const pam_message **msg, pam_response **resp, void *appdata_ptr ) {
	if (num_msg <= 0)
		return PAM_CONV_ERR;

	pam_response* reply = (pam_response*)calloc( num_msg, sizeof( pam_response ) );
	if (!reply)
		return PAM_SYSTEM_ERR;

	for (int replies=0; replies < num_msg; replies++) {
//		if (msg[replies]->msg)
//			printf( "PAM_MESSAGE: %s\n", msg[replies]->msg );

		if (msg[replies]->msg_style == PAM_PROMPT_ECHO_OFF) {
//			printf( "SEND PASSWORD: %s\n", appdata_ptr );
			reply[ replies ].resp_retcode = PAM_SUCCESS;
			reply[ replies ].resp = strdup( (const char*)appdata_ptr );
		} else {
			printf( "ABORT!\n" );
			free( reply );
			return PAM_CONV_ERR;
		};
	};

	printf( "conv function: PAM_SUCCESS\n" );
	*resp = reply;
	return PAM_SUCCESS;
};
};
#endif




bool XCAuthenticate::AuthenticatePAM( XCCredentials* creds, char* password ) {
	INFUNC( XCAuthenticate::AuthenticatePAM, NULL );

	printf( "AuthenticatePAM: user='%s'\n", creds->GetUserName() );
	bool result = false;

#ifdef USE_PAM
	// Ensure that we have been supplied a service name
	if (!*auth_parameter) {
		// Return an error to the system
		RAISETOOLSERROR_1PARM( ERR_AUTHENTICATION_ERROR, ERR_AUTH_PARAMETER );
	};

	int retval;
	pam_handle_t *pamh = NULL;
	pam_conv myconv;

	myconv.conv = PAMCallback;
	myconv.appdata_ptr = (void*)password;

	retval = pam_start( auth_parameter, creds->GetUserName(), &myconv, &pamh );
	if (retval != PAM_SUCCESS) {
		// Return the pam error
		RAISETOOLSERROR_1PARM( ERR_AUTHENTICATION_ERROR, pam_strerror( pamh, retval ) );
	};

	//PAM_DISALLOW_NULL_AUTHTOK );
	retval = pam_authenticate( pamh, 0 );

	if (retval == PAM_SUCCESS)
		retval = pam_acct_mgmt( pamh, 0 );

	// Did we authenticate?
	result = (retval == PAM_SUCCESS);
	if (!result)
		RAISETOOLSERROR_1PARM( ERR_AUTHENTICATION_ERROR, pam_strerror( pamh, retval ) );

	retval = pam_end( pamh, 0 );
	if (retval != PAM_SUCCESS)
		printf( "pam_end error: %s\n", pam_strerror( pamh, retval ) );
#else
	// This authentication method is not supported on this platform
	RAISETOOLSERROR( ERR_AUTHENTICATION_NOT_SUPPORTED );
#endif

	OUTFUNCRET( result );
};
